package concurrecy.util;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.*;

interface Counter {
    void increment();
    int get();
}

class CounterBase implements Counter {
    private int i = 0;

    @Override
    public void increment() {
        i ++;
    }

    @Override
    public int get() {
        return i;
    }
}

class CounterCas implements Counter {
    private int i = 0;

    private static Unsafe unsafe;
    private static long offset;

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe) theUnsafe.get(null);
            offset = unsafe.objectFieldOffset(CounterCas.class.getDeclaredField("i"));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void increment() {
        int t;
        do {
            t = i;
        } while(!unsafe.compareAndSwapInt(this, offset, t, t + 1));
    }

    @Override
    public int get() {
        return i;
    }
}

public class CounterDemo {
    final static int N = 50;
    public static void main(String[] args) throws InterruptedException {
        final Counter counter = new CounterCas();
        ExecutorService service = Executors.newCachedThreadPool();
        final CountDownLatch latch = new CountDownLatch(N), waitLatch = new CountDownLatch(N);

        long point = System.currentTimeMillis();
        for (int i = 0; i < N; i++) {
            service.execute(() -> {
                try {
                    // 等待所有线程一起执行
                    waitLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int j = 0; j < 10000; j++) {
                    counter.increment();
                }
                latch.countDown();
            });
            waitLatch.countDown();
        }
        // 等待所有线程都执行完
        latch.await();
        System.out.println("耗时：" + (System.currentTimeMillis() - point));
        service.shutdown();
        System.out.println("count: " + counter.get());
    }
}
